#include "GlobalHead.h"
#ifndef _PreComp_
# include <cfloat>
# include "InventorAll.h"
# include <QAction>
# include <QActionGroup>
# include <QApplication>
# include <QByteArray>
# include <QCursor>
# include <QList>
# include <QMenu>
# include <QMetaObject>
# include <QRegExp>
#endif
//#include <Inventor/sensors/SoTimerSensor.h>

#include "App/App_Application.h"
#include "NavigationStyle.h"
#include "View3DInventorViewer.h"
#include "Gui_Application.h"
#include "MenuManager.h"
#include "MouseSelection.h"

#include "CustomPlayer.h"

using namespace Gui;

namespace Gui {
struct NavigationStyleP {
    int animationsteps;
    int animationdelta;
//     SbVec3f focal1, focal2;
//     SbRotation endRotation;
//     SoTimerSensor * animsensor;

    NavigationStyleP()
    {
        this->animationsteps = 0;
    }
    //static void viewAnimationCB(void * data, SoSensor * sensor);
};
}

 NavigationStyleEvent::NavigationStyleEvent(const Base::Type& s)
   : QEvent(QEvent::User), t(s)
 {
 }
 
 NavigationStyleEvent::~NavigationStyleEvent()
 {
 }
 
 const Base::Type& NavigationStyleEvent::style() const
 { 
     return t;
 }

#define PRIVATE(ptr) (ptr->pimpl)
#define PUBLIC(ptr) (ptr->pub)

TYPESYSTEM_SOURCE_ABSTRACT(Gui::NavigationStyle,Base::BaseClass);

NavigationStyle::NavigationStyle() : viewer(0), mouseSelection(0),mInput(NULL)
,bLeft(0),bRight(0),bMiddle(0),mElapseTime(0)
{
	vMousePos.Set(0,0);
    PRIVATE(this) = new NavigationStyleP();
   // PRIVATE(this)->animsensor = new SoTimerSensor(NavigationStyleP::viewAnimationCB, this);
    initialize();
}

NavigationStyle::~NavigationStyle()
{
    finalize();
//     if (PRIVATE(this)->animsensor->isScheduled())
//         PRIVATE(this)->animsensor->unschedule();
//    delete PRIVATE(this)->animsensor;
    delete PRIVATE(this);
}

NavigationStyle& NavigationStyle::operator = (const NavigationStyle& ns)
{
//     this->panningplane = ns.panningplane;
//     this->menuenabled = ns.menuenabled;
//     this->spinanimatingallowed = ns.spinanimatingallowed;
    return *this;
}

void NavigationStyle::setViewer(View3DInventorViewer* view)
{
    this->viewer = view;
	mInput = static_cast<CKInputManager*>(viewer->m_Context->GetManagerByGuid(INPUT_MANAGER_GUID));
	mTimeManger = static_cast<CKTimeManager*>(viewer->m_Context->GetManagerByGuid(TIME_MANAGER_GUID));
}

void NavigationStyle::initialize()
{
    this->currentmode = NavigationStyle::IDLE;
//     this->prevRedrawTime = SbTime::getTimeOfDay();
//     this->spinanimatingallowed = TRUE;
//     this->spinsamplecounter = 0;
//     this->spinincrement = SbRotation::identity();
//     this->spinRotation.setValue(SbVec3f(0, 0, -1), 0);
// 
//     // FIXME: use a smaller sphere than the default one to have a larger
//     // area close to the borders that gives us "z-axis rotation"?
//     // 19990425 mortene.
//     this->spinprojector = new SbSphereSheetProjector(SbSphere(SbVec3f(0, 0, 0), 0.8f));
//     SbViewVolume volume;
//     volume.ortho(-1, 1, -1, 1, -1, 1);
//     this->spinprojector->setViewVolume(volume);
// 
//     this->log.size = 16;
//     this->log.position = new SbVec2s [ 16 ];
//     this->log.time = new SbTime [ 16 ];
//     this->log.historysize = 0;
// 
     this->menuenabled = TRUE;
     this->button1down = FALSE;
     this->button2down = FALSE;
     this->button3down = FALSE;
     this->ctrldown = FALSE;
     this->shiftdown = FALSE;
     this->altdown = FALSE;
      this->invertZoom = GetApp_Application().GetParameterGroupByPath
          ("User parameter:BaseApp/Preferences/View")->GetBool("InvertZoom",false);
}

void NavigationStyle::finalize()
{
//     delete this->spinprojector;
//     delete[] this->log.position;
//     delete[] this->log.time;
}

void NavigationStyle::interactiveCountInc(void)
{
    //viewer->interactiveCountInc();
}

void NavigationStyle::interactiveCountDec(void)
{
   // viewer->interactiveCountDec();
}

int NavigationStyle::getInteractiveCount(void) const
{
    return 0;//viewer->getInteractiveCount();
}

bool NavigationStyle::isViewing(void) const
{
   // return viewer->isViewing();
	return true;
}

void NavigationStyle::setViewing(bool enable)
{
    viewer->setViewing(enable);
}

bool NavigationStyle::isSeekMode(void) const
{
  //  return viewer->isSeekMode();
	return true;

}

void NavigationStyle::setSeekMode(bool enable)
{
    //viewer->setSeekMode(enable);
}

bool NavigationStyle::seekToPoint(const Vx2DVector screenpos)
{
    //return viewer->seekToPoint(screenpos);
	return true;
}

void NavigationStyle::seekToPoint(const VxVector& scenepos)
{
   // viewer->seekToPoint(scenepos);
}

void NavigationStyle::setCameraOrientation(const VxVector& rot)
{
//     SoCamera* cam = viewer->getCamera();
//     if (cam == 0) return;
// 
//     // Find global coordinates of focal point.
//     SbVec3f direction;
//     cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
//     PRIVATE(this)->focal1 = cam->position.getValue() +
//                             cam->focalDistance.getValue() * direction;
//     PRIVATE(this)->focal2 = PRIVATE(this)->focal1;
//     SoGetBoundingBoxAction action(viewer->getViewportRegion());
//     action.apply(viewer->getSceneGraph());
//     SbBox3f box = action.getBoundingBox();
//     if (!box.isEmpty()) {
//         rot.multVec(SbVec3f(0, 0, -1), direction);
//         //float s = (this->focal1 - box.getCenter()).dot(direction);
//         //this->focal2 = box.getCenter() + s * direction;
//         // setting the center of the overall bounding box as the future focal point
//         // seems to be a satisfactory solution
//         PRIVATE(this)->focal2 = box.getCenter();
//     }
// 
//     // avoid to interfere with spinning (fixes #3101462)
//     if (this->isAnimating())
//         this->stopAnimating();
// 
//     if (PRIVATE(this)->animsensor->isScheduled()) {
//         PRIVATE(this)->animsensor->unschedule();
//     }
// 
//     if (isAnimationEnabled()) {
//         // get the amount of movement
//         SbVec3f dir1, dir2;
//         SbRotation cam_rot = cam->orientation.getValue();
//         cam_rot.multVec(SbVec3f(0, 0, -1), dir1);
//         rot.multVec(SbVec3f(0, 0, -1), dir2);
//         float val = 0.5f*(1.0f + dir1.dot(dir2)); // value in range [0,1]
//         int div = (int)(val * 20.0f);
//         int steps = 20-div; // do it with max. 20 steps
// 
//         // check whether a movement is required
//         if (steps > 0) {
//             PRIVATE(this)->endRotation = rot; // this is the final camera orientation
//             this->spinRotation = cam_rot;
//             PRIVATE(this)->animationsteps = 5;
//             PRIVATE(this)->animationdelta = std::max<int>(100/steps, 5);
//             PRIVATE(this)->animsensor->setBaseTime(SbTime::getTimeOfDay());
//             PRIVATE(this)->animsensor->schedule();
//         }
//         else {
//             // due to possible round-off errors make sure that the
//             // exact orientation is set
//             cam->orientation.setValue(rot);
//         }
//     }
//     else {
//         // set to the given rotation
//         cam->orientation.setValue(rot);
//         cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
//         cam->position = PRIVATE(this)->focal2 - cam->focalDistance.getValue() * direction;
//     }
}

//void NavigationStyleP::viewAnimationCB(void * data, SoSensor * sensor)
//{
//     NavigationStyle* that = reinterpret_cast<NavigationStyle*>(data);
//     if (PRIVATE(that)->animationsteps > 0) {
//         // here the camera rotates from the current rotation to a given
//         // rotation (e.g. the standard views). To get this movement animated
//         // we calculate an interpolated rotation and update the view after
//         // each step
//         float step = std::min<float>((float)PRIVATE(that)->animationsteps/100.0f, 1.0f);
//         SbRotation slerp = SbRotation::slerp(that->spinRotation, PRIVATE(that)->endRotation, step);
//         SbVec3f focalpoint = (1.0f-step)*PRIVATE(that)->focal1 + step*PRIVATE(that)->focal2;
//         SoCamera* cam = that->viewer->getCamera();
//         SbVec3f direction;
//         cam->orientation.setValue(slerp);
//         cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
//         cam->position = focalpoint - cam->focalDistance.getValue() * direction;
// 
//         PRIVATE(that)->animationsteps += PRIVATE(that)->animationdelta;
//         if (PRIVATE(that)->animationsteps > 100) {
//             // now we have reached the end of the movement
//             PRIVATE(that)->animationsteps=0;
//             PRIVATE(that)->animsensor->unschedule();
//             // set to the actual given rotation
//             cam->orientation.setValue(PRIVATE(that)->endRotation);
//             cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
//             cam->position = PRIVATE(that)->focal2 - cam->focalDistance.getValue() * direction;
//         }
//     }
//}

void NavigationStyle::boxZoom(const VxBbox& box)
{
//     SoCamera* cam = viewer->getCamera();
//     if (!cam) return; // no camera 
//     const SbViewportRegion & vp = viewer->getViewportRegion();
//     SbViewVolume vv = cam->getViewVolume(vp.getViewportAspectRatio());
// 
//     short sizeX,sizeY;
//     box.getSize(sizeX, sizeY);
//     SbVec2s size = vp.getViewportSizePixels();
// 
//     // The bbox must not be empty i.e. width and length is zero, but it is possible that
//     // either width or length is zero
//     if (sizeX == 0 && sizeY == 0) 
//         return;
// 
//     // Get the new center in normalized pixel coordinates
//     short xmin,xmax,ymin,ymax;
//     box.getBounds(xmin,ymin,xmax,ymax);
//     const SbVec2f center((float) ((xmin+xmax)/2) / (float) SoQtMax((int)(size[0] - 1), 1),
//                          (float) (size[1]-(ymin+ymax)/2) / (float) SoQtMax((int)(size[1] - 1), 1));
// 
//     SbPlane plane = vv.getPlane(cam->focalDistance.getValue());
//     panCamera(cam,vp.getViewportAspectRatio(),plane, SbVec2f(0.5,0.5), center);
// 
//     // Set height or height angle of the camera
//     float scaleX = (float)sizeX/(float)size[0];
//     float scaleY = (float)sizeY/(float)size[1];
//     float scale = std::max<float>(scaleX, scaleY);
//     if (cam && cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
//         float height = static_cast<SoOrthographicCamera*>(cam)->height.getValue() * scale;
//         static_cast<SoOrthographicCamera*>(cam)->height = height;
//     }
//     else if (cam && cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
//         float height = static_cast<SoPerspectiveCamera*>(cam)->heightAngle.getValue() / 2.0f;
//         height = 2.0f * atan(tan(height) * scale);
//         static_cast<SoPerspectiveCamera*>(cam)->heightAngle = height;
//     }
}

void NavigationStyle::viewAll()
{
    // Get the bounding box of the scene
//     SoGetBoundingBoxAction action(viewer->getViewportRegion());
//     action.apply(viewer->getSceneGraph());
//     SbBox3f box = action.getBoundingBox();
//     if (box.isEmpty()) return;
// 
// #if 0
//     // check whether the box is very wide or tall, if not do nothing
//     float box_width, box_height, box_depth;
//     box.getSize( box_width, box_height, box_depth );
//     if (box_width < 5.0f*box_height && box_width < 5.0f*box_depth && 
//         box_height < 5.0f*box_width && box_height < 5.0f*box_depth && 
//         box_depth < 5.0f*box_width && box_depth < 5.0f*box_height )
//         return;
// #endif
// 
//     SoCamera* cam = viewer->getCamera();
//     if (!cam) return;
// 
//     SbViewVolume  vol = cam->getViewVolume();
//     if (vol.ulf == vol.llf)
//         return; // empty frustum (no view up vector defined)
//     SbVec2f s = vol.projectBox(box);
//     SbVec2s size = viewer->getSize();
// 
//     SbVec3f pt1, pt2, pt3, tmp;
//     vol.projectPointToLine( SbVec2f(0.0f,0.0f), pt1, tmp );
//     vol.projectPointToLine( SbVec2f(s[0],0.0f), pt2, tmp );
//     vol.projectPointToLine( SbVec2f(0.0f,s[1]), pt3, tmp );
// 
//     float cam_width = (pt2-pt1).length();
//     float cam_height = (pt3-pt1).length();
// 
//     // add a small border
//     cam_height = 1.08f * std::max<float>((cam_width*(float)size[1])/(float)size[0],cam_height);
// 
//     float aspect = cam->aspectRatio.getValue();
// 
//     if (cam->getTypeId() == SoPerspectiveCamera::getClassTypeId()) {
//         // set the new camera position dependent on the occupied space of projected bounding box
//         //SbVec3f direction = cam->position.getValue() - box.getCenter();
//         //float movelength = direction.length();
//         //direction.normalize();
//         //float fRatio = getViewportRegion().getViewportAspectRatio();
//         //if ( fRatio > 1.0f ) {
//         //  float factor = std::max<float>(s[0]/fRatio,s[1]);
//         //  movelength = factor * movelength;
//         //}
//         //else {
//         //    float factor = std::max<float>(s[0],s[1]/fRatio);
//         //    movelength = factor * movelength;
//         //}
//         //cam->position.setValue(box.getCenter() + direction * movelength);
//     }
//     else if (cam->getTypeId() == SoOrthographicCamera::getClassTypeId()) {
//         SoOrthographicCamera* ocam = (SoOrthographicCamera *)cam;  // safe downward cast, knows the type
//         if (aspect < 1.0f)
//             ocam->height = cam_height / aspect;
//         else
//             ocam->height = cam_height;
//     }
}

/** Rotate the camera by the given amount, then reposition it so we're
 * still pointing at the same focal point.
 */
// void NavigationStyle::reorientCamera(SoCamera * cam, const SbRotation & rot)
// {
//     if (cam == NULL) return;
// 
//     // Find global coordinates of focal point.
//     SbVec3f direction;
//     cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
//     SbVec3f focalpoint = cam->position.getValue() +
//                          cam->focalDistance.getValue() * direction;
// 
//     // Set new orientation value by accumulating the new rotation.
//     cam->orientation = rot * cam->orientation.getValue();
// 
//     // Reposition camera so we are still pointing at the same old focal point.
//     cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
//     cam->position = focalpoint - cam->focalDistance.getValue() * direction;
// }

void NavigationStyle::panCamera(CKCamera * cam, VxVector& camPos,/*float aspectratio, const VxPlane & panplane,*/
                                 Vx2DVector & currpos,  Vx2DVector & prevpos)
{
      if (cam == NULL || cam->GetTarget() == NULL) return; // can happen for empty scenegraph
    if (currpos == prevpos) return; // useless invocation


	VxVector CamerPos;
	cam->GetPosition(&CamerPos);



	VxVector cp;
    cam->GetCKContext()->GetPlayerRenderContext()->ScreenToViewpoint(currpos,&cp);
	cam->Transform(&cp,&cp);
	VxRay cpRay(CamerPos,cp);

	VxVector pp;
	cam->GetCKContext()->GetPlayerRenderContext()->ScreenToViewpoint(prevpos,&pp);
	cam->Transform(&pp,&pp);
	VxRay ppRay(CamerPos,pp);

	CK3dEntity* targetEnt = cam->GetTarget();
	VxVector tarPos;
	targetEnt->GetPosition(&tarPos);

   

    VxVector normal(0.0,0.0,1.0);
	cam->TransformVector(&normal,&normal);
	VxPlane plane(normal,tarPos);

	VxVector cp_intersect,pp_intersect;
	float cdist,pdist;

	VxIntersect::RayPlane(cpRay,plane,cp_intersect,cdist);
	VxIntersect::RayPlane(ppRay,plane,pp_intersect,pdist);


	
    
	//VxVector rPos = CamerPos - (cp_intersect - pp_intersect);
	VxVector tPos = tarPos - (cp_intersect - pp_intersect);

	//cam->SetPosition(&rPos);
	targetEnt->SetPosition(&tPos);


}

void NavigationStyle::pan(CKCamera* camera)
{
    // The plane we're projecting the mouse coordinates to get 3D
    // coordinates should stay the same during the whole pan
    // operation, so we should calculate this value here.
//     if (camera == NULL) { // can happen for empty scenegraph
//         this->panningplane = SbPlane(SbVec3f(0, 0, 1), 0);
//     }
//     else {
//         const SbViewportRegion & vp = viewer->getViewportRegion();
//         SbViewVolume vv = camera->getViewVolume(vp.getViewportAspectRatio());
//         this->panningplane = vv.getPlane(camera->focalDistance.getValue());
//     }
}

void NavigationStyle::panToCenter(const VxPlane & pplane, const Vx2DVector & currpos)
{
//     const SbViewportRegion & vp = viewer->getViewportRegion();
//     float ratio = vp.getViewportAspectRatio();
//     panCamera(viewer->getCamera(), ratio, pplane, SbVec2f(0.5,0.5), currpos);
}

/** Dependent on the camera type this will either shrink or expand the
 * height of the viewport (orthogonal camera) or move the camera
 * closer or further away from the focal point in the scene.
 */
void NavigationStyle::zoom(CKCamera * cam, float diffvalue)
{
    if (cam == NULL || cam->GetTarget() == NULL) return; // can happen for empty scenegraph
//     SoType t = cam->getTypeId();
//     SbName tname = t.getName();
// 
//     // This will be in the range of <0, ->>.
    CKSTRING nnn = cam->GetName();
	CK3dEntity* tobj = cam->GetTarget();
     float multiplicator = float(exp(diffvalue));

	 VxVector oldpos,targetpos;
	 cam->GetPosition(&oldpos);
	 tobj->GetPosition(&targetpos);

	  float oldfocaldist = Magnitude(targetpos - oldpos);
	  float newfocaldist = oldfocaldist * multiplicator;

	 VxVector cdir,cUp;

	 cam->GetOrientation(&cdir,&cUp);

	 VxVector newpos = oldpos + (newfocaldist - oldfocaldist) * -cdir;

	 float distorigo = Magnitude(newpos);

	 if(distorigo > float(sqrt(FLT_MAX)))
	 {

	 }
	 else
	 {
		 cam->SetPosition(&newpos);
	 }





// 	 VxVector camdir,camup;
// 	 cam->GetOrientation(camdir,camup);
// 	 const float olddist = cam->get
// 	 cam->SetPosition()
// 
//     if (t.isDerivedFrom(SoOrthographicCamera::getClassTypeId())) {
// 
//         // Since there's no perspective, "zooming" in the original sense
//         // of the word won't have any visible effect. So we just increase
//         // or decrease the field-of-view values of the camera instead, to
//         // "shrink" the projection size of the model / scene.
//         SoOrthographicCamera * oc = (SoOrthographicCamera *)cam;
//         oc->height = oc->height.getValue() * multiplicator;
// 
//     }
//     else {
//         // FrustumCamera can be found in the SmallChange CVS module (it's
//         // a camera that lets you specify (for instance) an off-center
//         // frustum (similar to glFrustum())
//         if (!t.isDerivedFrom(SoPerspectiveCamera::getClassTypeId()) &&
//             tname != "FrustumCamera") {
//  /*         static SbBool first = TRUE;
//             if (first) {
//                 SoDebugError::postWarning("SoGuiFullViewerP::zoom",
//                                           "Unknown camera type, "
//                                           "will zoom by moving position, but this might not be correct.");
//                 first = FALSE;
//             }*/
//         }
// 
//         const float oldfocaldist = cam->focalDistance.getValue();
//         const float newfocaldist = oldfocaldist * multiplicator;
// 
//         SbVec3f direction;
//         cam->orientation.getValue().multVec(SbVec3f(0, 0, -1), direction);
// 
//         const SbVec3f oldpos = cam->position.getValue();
//         const SbVec3f newpos = oldpos + (newfocaldist - oldfocaldist) * -direction;
// 
//         // This catches a rather common user interface "buglet": if the
//         // user zooms the camera out to a distance from origo larger than
//         // what we still can safely do floating point calculations on
//         // (i.e. without getting NaN or Inf values), the faulty floating
//         // point values will propagate until we start to get debug error
//         // messages and eventually an assert failure from core Coin code.
//         //
//         // With the below bounds check, this problem is avoided.
//         //
//         // (But note that we depend on the input argument ''diffvalue'' to
//         // be small enough that zooming happens gradually. Ideally, we
//         // should also check distorigo with isinf() and isnan() (or
//         // inversely; isinfite()), but those only became standardized with
//         // C99.)
//         const float distorigo = newpos.length();
//         // sqrt(FLT_MAX) == ~ 1e+19, which should be both safe for further
//         // calculations and ok for the end-user and app-programmer.
//         if (distorigo > float(sqrt(FLT_MAX))) {
//         }
//         else {
//             cam->position = newpos;
//             cam->focalDistance = newfocaldist;
//         }
//     }
}

// Calculate a zoom/dolly factor from the difference of the current
// cursor position and the last.
void NavigationStyle::zoomByCursor(const Vx2DVector & thispos, const Vx2DVector & prevpos)
{
    // There is no "geometrically correct" value, 20 just seems to give
    // about the right "feel".
   // zoom(viewer->getCamera(), (thispos[1] - prevpos[1]) * 10.0f/*20.0f*/);
}

/** Uses the sphere sheet projector to map the mouseposition onto
 * a 3D point and find a rotation from this and the last calculated point.
 */
void NavigationStyle::spin(CKCamera* pCamera,const VxVector & pointerpos)
{
	if(pCamera == NULL || pCamera->GetTarget() == NULL) return;

	CK3dEntity* pTarget = pCamera->GetTarget();

	if(pCamera->GetParent() == NULL)
		pCamera->SetParent(pTarget);

	 const float xAngle = pointerpos.x*0.005f;
	const float yAngle = pointerpos.y*0.005f;
	pTarget->Rotate(0.0f,1.0f,0.0f,-xAngle);
	pTarget->Rotate(1.0f,0.0f,0.0f,yAngle,pTarget);

// 	VxVector cPos;
// 	pCamera->GetPosition(&cPos);
// 	if(cPos.y <0.0f)
// 		pTarget->Rotate(1.0f,0.0f,0.0f,-xAngle,pTarget);

	//pTarget->Rotate(0.0f,1.0f,0.0f,yAngle);


	
//     if (this->log.historysize < 2) return;
//     assert(this->spinprojector != NULL);
// 
//     const SbViewportRegion & vp = viewer->getViewportRegion();
//     SbVec2s glsize(vp.getViewportSizePixels());
//     SbVec2f lastpos;
//     lastpos[0] = float(this->log.position[1][0]) / float(SoQtMax((int)(glsize[0]-1), 1));
//     lastpos[1] = float(this->log.position[1][1]) / float(SoQtMax((int)(glsize[1]-1), 1));
// 
//     this->spinprojector->project(lastpos);
//     SbRotation r;
//     this->spinprojector->projectAndGetRotation(pointerpos, r);
//     r.invert();
//     this->reorientCamera(viewer->getCamera(), r);
// 
//     // Calculate an average angle magnitude value to make the transition
//     // to a possible spin animation mode appear smooth.
// 
//     SbVec3f dummy_axis, newaxis;
//     float acc_angle, newangle;
//     this->spinincrement.getValue(dummy_axis, acc_angle);
//     acc_angle *= this->spinsamplecounter; // weight
//     r.getValue(newaxis, newangle);
//     acc_angle += newangle;
// 
//     this->spinsamplecounter++;
//     acc_angle /= this->spinsamplecounter;
//     // FIXME: accumulate and average axis vectors aswell? 19990501 mortene.
//     this->spinincrement.setValue(newaxis, acc_angle);
// 
//     // Don't carry too much baggage, as that'll give unwanted results
//     // when the user quickly trigger (as in "click-drag-release") a spin
//     // animation.
//     if (this->spinsamplecounter > 3) this->spinsamplecounter = 3;
}

bool NavigationStyle::doSpin()
{
//     if (this->log.historysize >= 3) {
//         SbTime stoptime = (SbTime::getTimeOfDay() - this->log.time[0]);
//         if (this->spinanimatingallowed && stoptime.getValue() < 0.100) {
//             const SbViewportRegion & vp = viewer->getViewportRegion();
//             const SbVec2s glsize(vp.getViewportSizePixels());
//             SbVec3f from = this->spinprojector->project(SbVec2f(float(this->log.position[2][0]) / float(SoQtMax(glsize[0]-1, 1)),
//                                                                 float(this->log.position[2][1]) / float(SoQtMax(glsize[1]-1, 1))));
//             SbVec3f to = this->spinprojector->project(this->lastmouseposition);
//             SbRotation rot = this->spinprojector->getRotation(from, to);
// 
//             SbTime delta = (this->log.time[0] - this->log.time[2]);
//             double deltatime = delta.getValue();
//             rot.invert();
//             rot.scaleAngle(float(0.200 / deltatime));
// 
//             SbVec3f axis;
//             float radians;
//             rot.getValue(axis, radians);
//             if ((radians > 0.01f) && (deltatime < 0.300)) {
//                 this->spinRotation = rot;
//                 return TRUE;
//             }
//         }
//     }

    return FALSE;
}

void NavigationStyle::updateAnimation()
{
//     SbTime now = SbTime::getTimeOfDay();
//     double secs = now.getValue() -  prevRedrawTime.getValue();
//     this->prevRedrawTime = now;
// 
//     if (this->isAnimating()) {
//         // here the camera rotates around a fix axis
//         SbRotation deltaRotation = this->spinRotation;
//         deltaRotation.scaleAngle(secs * 5.0);
//         this->reorientCamera(viewer->getCamera(), deltaRotation);
//     }
}

void NavigationStyle::redraw()
{
//     if (mouseSelection)
//         mouseSelection->redraw();
}

// bool NavigationStyle::handleEventInForeground(const SoEvent* const e)
// {
//     SoHandleEventAction action(viewer->getViewportRegion());
//     action.setEvent(e);
//     action.apply(viewer->foregroundroot);
//     return action.isHandled();
//}

/*!
  Decide if it should be possible to start a spin animation of the
  model in the viewer by releasing the mouse button while dragging.

  If the \a enable flag is \c FALSE and we're currently animating, the
  spin will be stopped.
*/
void
NavigationStyle::setAnimationEnabled(const bool enable)
{
//     this->spinanimatingallowed = enable;
//     if (!enable && this->isAnimating()) { this->stopAnimating(); }
}

/*!
  Query whether or not it is possible to start a spinning animation by
  releasing the left mouse button while dragging the mouse.
*/

bool
NavigationStyle::isAnimationEnabled(void) const
{
   // return this->spinanimatingallowed;
	return true;
}

/*!
  Query if the model in the viewer is currently in spinning mode after
  a user drag.
*/
bool NavigationStyle::isAnimating(void) const
{
    return this->currentmode == NavigationStyle::SPINNING;

	//return true;
}

/*!
 * Starts programmatically the viewer in animation mode. The given axis direction
 * is always in screen coordinates, not in world coordinates.
 */
void NavigationStyle::startAnimating(const VxVector& axis, float velocity)
{
//     if (!isAnimationEnabled()) return;
// 
//     this->prevRedrawTime = SbTime::getTimeOfDay();
//     this->spinincrement = SbRotation::identity();
//     SbRotation rot;
//     rot.setValue(axis, velocity);
// 
//     this->setViewing(true);
//     this->setViewingMode(NavigationStyle::SPINNING);
//     this->spinRotation = rot;
}

void NavigationStyle::stopAnimating(void)
{
//     if (this->currentmode != NavigationStyle::SPINNING) {
//         return;
//     }
//     this->setViewingMode(this->isViewing() ? 
//         NavigationStyle::IDLE : NavigationStyle::INTERACT);
}

void NavigationStyle::setZoomInverted(bool on)
{
   // this->invertZoom = on;
}

bool NavigationStyle::isZoomInverted() const
{
    return 0;//this->invertZoom;
}

void NavigationStyle::startSelection(AbstractMouseSelection* mouse)
{
     if (!mouse)
         return;
   
     mouseSelection = mouse;
     mouseSelection->grabMouseModel(viewer);
}

void NavigationStyle::startSelection(NavigationStyle::SelectionMode mode)
{
     if (mouseSelection)
         return;
     if (isSelecting())
         stopSelection();
   
     switch (mode)
     {
     case Lasso:
         mouseSelection = new PolyPickerSelection();
         break;
     case Rectangle:
         mouseSelection = new RectangleSelection();
         break;
     case BoxZoom:
         mouseSelection = new BoxZoomSelection();
         break;
     case Clip:
         mouseSelection = new PolyClipSelection();
         break;
     default:
         break;
     }
 
     if (mouseSelection)
         mouseSelection->grabMouseModel(viewer);
}

void NavigationStyle::stopSelection()
{
//     pcPolygon.clear();
     delete mouseSelection; 
     mouseSelection = 0;
}

bool NavigationStyle::isSelecting() const
{
    return (mouseSelection ? TRUE : FALSE);
}

// const std::vector<Vx2DVector>& NavigationStyle::getPolygon(SbBool* clip_inner) const
// {
//     if (clip_inner)
//         *clip_inner = this->clipInner;
//     return pcPolygon;
// }
// 
// // This method adds another point to the mouse location log, used for spin
// // animation calculations.
// void NavigationStyle::addToLog(const SbVec2s pos, const SbTime time)
// {
//     // In case someone changes the const size setting at the top of this
//     // file too small.
//     assert (this->log.size > 2 && "mouse log too small!");
// 
//     if (this->log.historysize > 0 && pos == this->log.position[0]) {
// #if SOQt_DEBUG && 0 // debug
//         // This can at least happen under SoQt.
//         SoDebugError::postInfo("NavigationStyle::addToLog", "got position already!");
// #endif // debug
//         return;
//     }
// 
//     int lastidx = this->log.historysize;
//     // If we've filled up the log, we should throw away the last item:
//     if (lastidx == this->log.size) { lastidx--; }
// 
//     assert(lastidx < this->log.size);
//     for (int i = lastidx; i > 0; i--) {
//         this->log.position[i] = this->log.position[i-1];
//         this->log.time[i] = this->log.time[i-1];
//     }
// 
//     this->log.position[0] = pos;
//     this->log.time[0] = time;
//     if (this->log.historysize < this->log.size)
//         this->log.historysize += 1;
// }

// This method "clears" the mouse location log, used for spin
// animation calculations.
// void NavigationStyle::clearLog(void)
// {
//     this->log.historysize = 0;
// }

// The viewer is a state machine, and all changes to the current state
// are made through this call.
void NavigationStyle::setViewingMode(const ViewerMode newmode)
{
	     const ViewerMode oldmode = this->currentmode;
     if (newmode == oldmode) { return; }
 
     switch (newmode) {
     case DRAGGING:
         // Set up initial projection point for the projector object when
         // first starting a drag operation.
//          this->spinprojector->project(this->lastmouseposition);
//          this->interactiveCountInc();
//          this->clearLog();
         break;
 
     case SPINNING:
//          this->interactiveCountInc();
//          viewer->scheduleRedraw();
         break;
 
     case PANNING:
//          pan(viewer->getCamera());
//          this->interactiveCountInc();
         break;
 
     case ZOOMING:
        // this->interactiveCountInc();
         break;
 
     case BOXZOOM:
       //  this->interactiveCountInc();
         break;
 
     default: // include default to avoid compiler warnings.
         break;
     }
 
     switch (oldmode) {
     case SPINNING:
     case DRAGGING:
     case PANNING:
     case ZOOMING:
     case BOXZOOM:
       //  this->interactiveCountDec();
         break;
 
     default:
         break;
     }
 
     viewer->setCursorRepresentation(newmode);
     this->currentmode = newmode;
}

int NavigationStyle::getViewingMode() const
{
    return 0;//(int)this->currentmode;
}

bool NavigationStyle::processEvent(/*const SoEvent * const ev*/)
{
    // If we're in picking mode then all events must be redirected to the
    // appropriate mouse model.
//     if (mouseSelection) {
//         int hd=mouseSelection->handleEvent(ev,viewer->getViewportRegion());
//         if (hd==AbstractMouseSelection::Continue||
//             hd==AbstractMouseSelection::Restart) {
//             return TRUE;
//         }
//         else if (hd==AbstractMouseSelection::Finish) {
//             pcPolygon = mouseSelection->getPositions();
//             clipInner = mouseSelection->isInner();
//             delete mouseSelection; mouseSelection = 0;
//             return NavigationStyle::processSoEvent(ev);
//         }
//         else if (hd==AbstractMouseSelection::Cancel) {
//             pcPolygon.clear();
//             delete mouseSelection; mouseSelection = 0;
//             return NavigationStyle::processSoEvent(ev);
//         }
//     }
// 


    const ViewerMode curmode = this->currentmode;
// 
     bool processed = FALSE;
     processed = this->processSoEvent();
// 
//     // check for left click without selecting something
//     if (curmode == NavigationStyle::SELECTION && !processed) {
//         if (ev->getTypeId().isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
//             SoMouseButtonEvent * const e = (SoMouseButtonEvent *) ev;
//             if (SoMouseButtonEvent::isButtonReleaseEvent(e,SoMouseButtonEvent::BUTTON1)) {
//                 Gui::Selection().clearSelection();
//             }
//         }
//     }
// 
//     return processed;

	return  true;
}

bool NavigationStyle::processSoEvent(/*const SoEvent * const ev*/)
{
    return viewer->processSoEventBase(/*ev*/);
}

// void NavigationStyle::setPopupMenuEnabled(const bool on)
// {
//    // this->menuenabled = on;
// }
// 
// bool NavigationStyle::isPopupMenuEnabled(void) const
// {
//     return this->menuenabled;
// }

void NavigationStyle::openPopupMenu(const Vx2DVector& position)
{
    // ask workbenches and view provider, ...
//     MenuItem* view = new MenuItem;
//     Gui::Application::Instance->setupContextMenu("View", view);
// 
//     QMenu contextMenu(viewer->getGLWidget());
//     QMenu subMenu;
//     QActionGroup subMenuGroup(&subMenu);
//     subMenuGroup.setExclusive(true);
//     subMenu.setTitle(QObject::tr("Navigation styles"));
// 
//     MenuManager::getInstance()->setupContextMenu(view,contextMenu);
//     contextMenu.addMenu(&subMenu);
// 
//     // add submenu at the end to select navigation style
//     QRegExp rx(QString::fromAscii("^\\w+::(\\w+)Navigation\\w+$"));
//     std::vector<Base::Type> types;
//     Base::Type::getAllDerivedFrom(UserNavigationStyle::getClassTypeId(), types);
//     for (std::vector<Base::Type>::iterator it = types.begin(); it != types.end(); ++it) {
//         if (*it != UserNavigationStyle::getClassTypeId()) {
//             QString data = QString::fromAscii(it->getName());
//             QString name = data.mid(data.indexOf(QLatin1String("::"))+2);
//             if (rx.indexIn(data) > -1) {
//                 name = QObject::tr("%1 navigation").arg(rx.cap(1));
//                 QAction* item = subMenuGroup.addAction(name);
//                 item->setData(QByteArray(it->getName()));
//                 item->setCheckable(true);
//                 if (*it == this->getTypeId())
//                     item->setChecked(true);
//                 subMenu.addAction(item);
//             }
//         }
//     }
// 
//     delete view;
//     QAction* used = contextMenu.exec(QCursor::pos());
//     if (used && subMenuGroup.actions().indexOf(used) >= 0 && used->isChecked()) {
//         QByteArray type = used->data().toByteArray();
//         QWidget* widget = viewer->getWidget();
//         while (widget && !widget->inherits("Gui::View3DInventor"))
//             widget = widget->parentWidget();
//         if (widget) {
//             // this is the widget where the viewer is embedded
//             Base::Type style = Base::Type::fromName((const char*)type);
//             if (style != this->getTypeId()) {
//                 QEvent* event = new NavigationStyleEvent(style);
//                 QApplication::postEvent(widget, event);
//             }
//         }
//     }
}

// ----------------------------------------------------------------------------------

TYPESYSTEM_SOURCE_ABSTRACT(Gui::UserNavigationStyle,Gui::NavigationStyle);

// ----------------------------------------------------------------------------------

/* TRANSLATOR Gui::InventorNavigationStyle */

TYPESYSTEM_SOURCE(Gui::InventorNavigationStyle, Gui::UserNavigationStyle);

InventorNavigationStyle::InventorNavigationStyle()
{
}

InventorNavigationStyle::~InventorNavigationStyle()
{
}

const char* InventorNavigationStyle::mouseButtons(ViewerMode mode)
{
    switch (mode) {
    case NavigationStyle::SELECTION:
        return QT_TR_NOOP("Press CTRL and left mouse button");
    case NavigationStyle::PANNING:
        return QT_TR_NOOP("Press middle mouse button");
    case NavigationStyle::DRAGGING:
        return QT_TR_NOOP("Press left mouse button");
    case NavigationStyle::ZOOMING:
        return QT_TR_NOOP("Scroll middle mouse button");
    default:
        return "No description";
    }
}

bool InventorNavigationStyle::processSoEvent(/*const SoEvent * const ev*/)
{
    // Events when in "ready-to-seek" mode are ignored, except those
    // which influence the seek mode itself -- these are handled further
    // up the inheritance hierarchy.
//     if (this->isSeekMode()) { return inherited::processSoEvent(ev); }
// 
//     const SoType type(ev->getTypeId());
// 
//     const SbViewportRegion & vp = viewer->getViewportRegion();
//     const SbVec2s size(vp.getViewportSizePixels());
//     const SbVec2f prevnormalized = this->lastmouseposition;
//     const SbVec2s pos(ev->getPosition());
//     const SbVec2f posn((float) pos[0] / (float) SoQtMax((int)(size[0] - 1), 1),
//                        (float) pos[1] / (float) SoQtMax((int)(size[1] - 1), 1));
// 
//     this->lastmouseposition = posn;
// 
//     // Set to TRUE if any event processing happened. Note that it is not
//     // necessary to restrict ourselves to only do one "action" for an
//     // event, we only need this flag to see if any processing happened
//     // at all.
//     SbBool processed = FALSE;
// 
//     const ViewerMode curmode = this->currentmode;
//     ViewerMode newmode = curmode;
// 
//     // Mismatches in state of the modifier keys happens if the user
//     // presses or releases them outside the viewer window.
//     if (this->ctrldown != ev->wasCtrlDown()) {
//         this->ctrldown = ev->wasCtrlDown();
//     }
//     if (this->shiftdown != ev->wasShiftDown()) {
//         this->shiftdown = ev->wasShiftDown();
//     }
//     if (this->altdown != ev->wasAltDown()) {
//         this->altdown = ev->wasAltDown();
//     }
// 
//     // give the nodes in the foreground root the chance to handle events (e.g color bar)
//     if (!processed && !viewer->isEditing()) {
//         processed = handleEventInForeground(ev);
//         if (processed)
//             return TRUE;
//     }
// 
//     // Keyboard handling
//     if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId())) {
//         const SoKeyboardEvent * const event = (const SoKeyboardEvent *) ev;
//         const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
//         switch (event->getKey()) {
//         case SoKeyboardEvent::LEFT_CONTROL:
//         case SoKeyboardEvent::RIGHT_CONTROL:
//             this->ctrldown = press;
//             break;
//         case SoKeyboardEvent::LEFT_SHIFT:
//         case SoKeyboardEvent::RIGHT_SHIFT:
//             this->shiftdown = press;
//             break;
//         case SoKeyboardEvent::LEFT_ALT:
//         case SoKeyboardEvent::RIGHT_ALT:
//             this->altdown = press;
//             break;
//         case SoKeyboardEvent::H:
//             processed = TRUE;
//             viewer->saveHomePosition();
//             break;
//         case SoKeyboardEvent::S:
//         case SoKeyboardEvent::HOME:
//         case SoKeyboardEvent::LEFT_ARROW:
//         case SoKeyboardEvent::UP_ARROW:
//         case SoKeyboardEvent::RIGHT_ARROW:
//         case SoKeyboardEvent::DOWN_ARROW:
//             if (!this->isViewing())
//                 this->setViewing(true);
//             break;
//         default:
//             break;
//         }
//     }
// 
//     // Mouse Button / Spaceball Button handling
//     if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId())) {
//         const SoMouseButtonEvent * const event = (const SoMouseButtonEvent *) ev;
//         const int button = event->getButton();
//         const SbBool press = event->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
// 
//         // SoDebugError::postInfo("processSoEvent", "button = %d", button);
//         switch (button) {
//         case SoMouseButtonEvent::BUTTON1:
//             this->button1down = press;
//             if (press && ev->wasShiftDown() &&
//                 (this->currentmode != NavigationStyle::SELECTION)) {
//                 this->centerTime = ev->getTime();
//                 float ratio = vp.getViewportAspectRatio();
//                 SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio);
//                 this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue());
//                 this->lockrecenter = FALSE;
//             }
//             else if (!press && ev->wasShiftDown() &&
//                 (this->currentmode != NavigationStyle::SELECTION)) {
//                 SbTime tmp = (ev->getTime() - this->centerTime);
//                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
//                 // is it just a left click?
//                 if (tmp.getValue() < dci && !this->lockrecenter) {
//                     if (!this->seekToPoint(pos)) {
//                         panToCenter(panningplane, posn);
//                         this->interactiveCountDec();
//                     }
//                     processed = TRUE;
//                 }
//             }
//             else if (press && (this->currentmode == NavigationStyle::SEEK_WAIT_MODE)) {
//                 newmode = NavigationStyle::SEEK_MODE;
//                 this->seekToPoint(pos); // implicitly calls interactiveCountInc()
//                 processed = TRUE;
//             }
//             else if (press && (this->currentmode == NavigationStyle::IDLE)) {
//                 this->setViewing(true);
//                 processed = TRUE;
//             }
//             else if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
//                 this->setViewing(false);
//                 processed = TRUE;
//             }
//             else if (viewer->isEditing() && (this->currentmode == NavigationStyle::SPINNING)) {
//                 processed = TRUE;
//             }
//             this->lockrecenter = TRUE;
//             break;
//         case SoMouseButtonEvent::BUTTON2:
//             // If we are in edit mode then simply ignore the RMB events
//             // to pass the event to the base class.
//             this->lockrecenter = TRUE;
//             if (!viewer->isEditing()) {
//                 // If we are in zoom or pan mode ignore RMB events otherwise
//                 // the canvas doesn't get any release events 
//                 if (this->currentmode != NavigationStyle::ZOOMING && 
//                     this->currentmode != NavigationStyle::PANNING) {
//                     if (this->isPopupMenuEnabled()) {
//                         if (!press) { // release right mouse button
//                             this->openPopupMenu(event->getPosition());
//                         }
//                     }
//                 }
//             }
//             break;
//         case SoMouseButtonEvent::BUTTON3:
//             if (press) {
//                 this->centerTime = ev->getTime();
//                 float ratio = vp.getViewportAspectRatio();
//                 SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio);
//                 this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue());
//                 this->lockrecenter = FALSE;
//             }
//             else {
//                 SbTime tmp = (ev->getTime() - this->centerTime);
//                 float dci = (float)QApplication::doubleClickInterval()/1000.0f;
//                 // is it just a middle click?
//                 if (tmp.getValue() < dci && !this->lockrecenter) {
//                     if (!this->seekToPoint(pos)) {
//                         panToCenter(panningplane, posn);
//                         this->interactiveCountDec();
//                     }
//                     processed = TRUE;
//                 }
//             }
//             this->button3down = press;
//             break;
//         case SoMouseButtonEvent::BUTTON4:
//             if (this->invertZoom)
//                 zoom(viewer->getCamera(), -0.05f);
//             else
//                 zoom(viewer->getCamera(), 0.05f);
//             processed = TRUE;
//             break;
//         case SoMouseButtonEvent::BUTTON5:
//             if (this->invertZoom)
//                 zoom(viewer->getCamera(), 0.05f);
//             else
//                 zoom(viewer->getCamera(), -0.05f);
//             processed = TRUE;
//             break;
//         default:
//             break;
//         }
//     }
// 
//     // Mouse Movement handling
//     if (type.isDerivedFrom(SoLocation2Event::getClassTypeId())) {
//         this->lockrecenter = TRUE;
//         const SoLocation2Event * const event = (const SoLocation2Event *) ev;
//         if (this->currentmode == NavigationStyle::ZOOMING) {
//             this->zoomByCursor(posn, prevnormalized);
//             processed = TRUE;
//         }
//         else if (this->currentmode == NavigationStyle::PANNING) {
//             float ratio = vp.getViewportAspectRatio();
//             panCamera(viewer->getCamera(), ratio, this->panningplane, posn, prevnormalized);
//             processed = TRUE;
//         }
//         else if (this->currentmode == NavigationStyle::DRAGGING) {
//             this->addToLog(event->getPosition(), event->getTime());
//             this->spin(posn);
//             processed = TRUE;
//         }
//     }
// 
//     // Spaceball & Joystick handling
//     if (type.isDerivedFrom(SoMotion3Event::getClassTypeId())) {
//         SoMotion3Event * const event = (SoMotion3Event *) ev;
//         SoCamera * const camera = viewer->getCamera();
//         if (camera) {
//             SbVec3f dir = event->getTranslation();
//             camera->orientation.getValue().multVec(dir,dir);
//             camera->position = camera->position.getValue() + dir;
//             camera->orientation = 
//                 event->getRotation() * camera->orientation.getValue();
//             processed = TRUE;
//         }
//     }
// 
//     enum {
//         BUTTON1DOWN = 1 << 0,
//         BUTTON3DOWN = 1 << 1,
//         CTRLDOWN =    1 << 2,
//         SHIFTDOWN =   1 << 3
//     };
//     unsigned int combo =
//         (this->button1down ? BUTTON1DOWN : 0) |
//         (this->button3down ? BUTTON3DOWN : 0) |
//         (this->ctrldown ? CTRLDOWN : 0) |
//         (this->shiftdown ? SHIFTDOWN : 0);
// 
//     switch (combo) {
//     case 0:
//         if (curmode == NavigationStyle::SPINNING) { break; }
//         newmode = NavigationStyle::IDLE;
// 
//         if (curmode == NavigationStyle::DRAGGING) {
//             if (doSpin())
//                 newmode = NavigationStyle::SPINNING;
//         }
//         break;
//     case BUTTON1DOWN:
//         newmode = NavigationStyle::DRAGGING;
//         break;
//     case BUTTON3DOWN:
//     case SHIFTDOWN|BUTTON1DOWN:
//         newmode = NavigationStyle::PANNING;
//         break;
//     case CTRLDOWN:
//     case CTRLDOWN|BUTTON1DOWN:
//     case CTRLDOWN|SHIFTDOWN:
//     case CTRLDOWN|SHIFTDOWN|BUTTON1DOWN:
//         newmode = NavigationStyle::SELECTION;
//         break;
//     case BUTTON1DOWN|BUTTON3DOWN:
//     case CTRLDOWN|BUTTON3DOWN:
//         newmode = NavigationStyle::ZOOMING;
//         break;
// 
//         // There are many cases we don't handle that just falls through to
//         // the default case, like SHIFTDOWN, CTRLDOWN, CTRLDOWN|SHIFTDOWN,
//         // SHIFTDOWN|BUTTON3DOWN, SHIFTDOWN|CTRLDOWN|BUTTON3DOWN, etc.
//         // This is a feature, not a bug. :-)
//         //
//         // mortene.
// 
//     default:
//         // The default will make a spin stop and otherwise not do
//         // anything.
//         if ((curmode != NavigationStyle::SEEK_WAIT_MODE) &&
//             (curmode != NavigationStyle::SEEK_MODE)) {
//             newmode = NavigationStyle::IDLE;
//         }
//         break;
//     }
// 
//     if (newmode != curmode) {
//         this->setViewingMode(newmode);
//     }
// 
//     // If not handled in this class, pass on upwards in the inheritance
//     // hierarchy.
//     if ((curmode == NavigationStyle::SELECTION || viewer->isEditing()) && !processed)
//         processed = inherited::processSoEvent(ev);
//     else
//         return TRUE;
// 
//     return processed;
      return true;
}

// ----------------------------------------------------------------------------------

/* TRANSLATOR Gui::CADNavigationStyle */

TYPESYSTEM_SOURCE(Gui::CADNavigationStyle, Gui::UserNavigationStyle);

CADNavigationStyle::CADNavigationStyle() : lockButton1(FALSE),mRct(NULL)
{
  
}

CADNavigationStyle::~CADNavigationStyle()
{
}

const char* CADNavigationStyle::mouseButtons(ViewerMode mode)
{
    switch (mode) {
    case NavigationStyle::SELECTION:
        return QT_TR_NOOP("Press left mouse button");
    case NavigationStyle::PANNING:
        return QT_TR_NOOP("Press middle mouse button");
    case NavigationStyle::DRAGGING:
        return QT_TR_NOOP("Press left and middle mouse button");
    case NavigationStyle::ZOOMING:
        return QT_TR_NOOP("Scroll middle mouse button");
    default:
        return "No description";
    }
}

bool CADNavigationStyle::processSoEvent(/*const SoEvent * const ev*/)
{
	if(mInput == NULL)
		return false;

	if(mRct == NULL)
	{
		//mRct = viewer->m_Context->GetPlayerRenderContext();
		mRct = CCustomPlayer::Instance().GetRenderContext();
	}

	Vx2DVector prevnormalized = this->lastmouseposition;
	Vx2DVector posn;
	mInput->GetMousePosition(posn);
	mRct->ScreenToClient(&posn);
	this->lastmouseposition = posn;

	VxRect rt;
	//viewer->m_Context->GetPlayerRenderContext()->GetViewRect(rt);
	CCustomPlayer::Instance().getViewRect(&rt);
	//Vx2DVector 
	//viewer->m_Context->GetPlayerRenderContext()->ScreenToClient(rt.top)

	if(!rt.IsInside(posn))
		return true;


	if (!this->isSeekMode() && this->isViewing())
		this->setViewing(false); // by default disable viewing mode to render the scene



   VxVector campos;

   BOOL processed  = FALSE;

   const ViewerMode curmode = this->currentmode; 
   ViewerMode newmode = curmode;

   if(mInput->IsKeyDown(CKKEY_LCONTROL))
    ctrldown = true;
   else
	 ctrldown = false;

   if(mInput->IsKeyDown(CKKEY_LSHIFT))
	   shiftdown = true;
   else
	   shiftdown = false;

   if(mInput->IsKeyDown(CKKEY_LMENU))
	   altdown = true;
   else
	   altdown = false;

 //  ctrldown = shiftdown = altdown = false;
  // button1down = button2down = button3down = false;
	CKDWORD key = 0;


	int keynum = mInput->GetNumberOfKeyInBuffer();
	for (int i = 0; i < keynum; i++)
	{
		if(mInput->GetKeyFromBuffer(i,key) == KEY_PRESSED)
		{
			switch (key)
			{
			case CKKEY_LCONTROL:
					 this->ctrldown = true;
				break;
			case CKKEY_LSHIFT:
				   this->shiftdown = true;
				break;
			case CKKEY_LMENU:
				 this->altdown = true;
			case CKKEY_DOWN:
				if (!this->isViewing())
					this->setViewing(true);
				break;
			default:
				break;


			}
		}
	}


	Vx2DVector oldMousePos;
	oldMousePos = vMousePos;

	Vx2DVector mousePos;

	mInput->GetMousePosition(mousePos,TRUE);
	vMousePos = mousePos;

	

	VxVector v3;
	mInput->GetMouseRelativePosition(v3);

	float wheelDir = v3.z;


	CKBOOL left_old, left_new;  // we handle the left mouse button
	left_old= bLeft;

	left_new = mInput->IsMouseButtonDown(CK_MOUSEBUTTON_LEFT);
	bLeft = left_new;




	CKBOOL middle_old, middle_new;  // we handle the middle mouse button

	middle_old = bMiddle;
	middle_new = mInput->IsMouseButtonDown(CK_MOUSEBUTTON_MIDDLE);
	bMiddle = middle_new;


	CKBOOL right_old, right_new;  // we handle the right mouse button

	right_old = bRight;
	right_new = mInput->IsMouseButtonDown(CK_MOUSEBUTTON_RIGHT);
	bRight = right_new;



	//double click, get delta time
	int dblClkSpeed = 500;

	int deltaTime = mElapseTime;

	int oldDT=deltaTime;
	if (deltaTime!=-1 && (int)(deltaTime & 0x3fffffff)>=0)
		deltaTime = (int)(deltaTime & 0x3fffffff) + (int)mTimeManger->GetLastDeltaTime() + (deltaTime & 0xc0000000) ;

	bool press = false;
	CKBYTE mousesState[4];
	mInput->GetMouseButtonsState(mousesState);
	for (int i = 0; i < 3 ; ++i)
	{
		if((mousesState[i]) == KEY_PRESSED)
		{
			press = true;
			break;
		}
	}

	//left button down
	//////////////////////////////////////////////////////////////////////////
	if( !left_old && left_new) {

		this->button1down = true;
		
		if((this->currentmode == NavigationStyle::SEEK_WAIT_MODE))
		{
			newmode = NavigationStyle::SEEK_MODE;
			this->seekToPoint(mousePos);
			processed = TRUE;
		}
		else if((this->currentmode == NavigationStyle::PANNING || this->currentmode == NavigationStyle::ZOOMING))
		{
			this->centerTime = mTimeManger->GetLastDeltaTime();
			newmode = NavigationStyle::DRAGGING;
			processed = TRUE;
		}

	}
	//left buuton up
	if( left_old && !left_new) {

		// 	      if (!press && (this->currentmode == NavigationStyle::DRAGGING)) {
		// 			SbTime tmp = (ev->getTime() - this->centerTime);
		// 			float dci = (float)QApplication::doubleClickInterval()/1000.0f;
		// 			if (tmp.getValue() < dci) {
		// 				newmode = NavigationStyle::ZOOMING;
		// 			}
		this->button1down = false;
		processed = TRUE;
	}

	//}
	//right button down
	//////////////////////////////////////////////////////////////////////////    
	if( !right_old && right_new) {
   
		  this->button2down = true;

	}
	//right button up
	if( right_old && !right_new) {

		  this->button2down = false;

	}
	// Middle Button down
	//////////////////////////////////////////////////////////////////////////
	if( !middle_old && middle_new) {

		viewer->getCamera()->GetPosition(&campos);
// 		this->centerTime = ev->getTime();
// 		float ratio = vp.getViewportAspectRatio();
// 		SbViewVolume vv = viewer->getCamera()->getViewVolume(ratio);
// 		this->panningplane = vv.getPlane(viewer->getCamera()->focalDistance.getValue());
		this->lockrecenter = FALSE;
		 this->button3down = true;


	}
	//Midlle button up
	if( middle_old && !middle_new) {

// 		SbTime tmp = (ev->getTime() - this->centerTime);
// 		float dci = (float)QApplication::doubleClickInterval()/1000.0f;
// 		// is it just a middle click?
// 		if (tmp.getValue() < dci && !this->lockrecenter) {
// 			if (!this->seekToPoint(pos)) {
// 				panToCenter(panningplane, posn);
// 				this->interactiveCountDec();
// 			}

			 this->button3down = false;
			 processed = TRUE;

	}
	//roll
	//////////////////////////////////////////////////////////////////////////
	if(wheelDir) {

		if(wheelDir >0)
			zoom(viewer->getCamera(),0.05f);
		else if(wheelDir <0)
			zoom(viewer->getCamera(),-0.05f);	


		processed = TRUE;

	}
	// left db1 click
	//////////////////////////////////////////////////////////////////////////
	if((!left_old && left_new) )
	{
		if (deltaTime==-1 || (deltaTime & 0xc0000000) != 0)//bit flag is not 0<=>left
			deltaTime=0;
		else if ((int)(deltaTime & 0x3fffffff)<=dblClkSpeed)
		{
			deltaTime=-1;

			//oneactive = TRUE;
		}
	}
	//right dbl click
	if((!right_old && right_new))
	{
		if (deltaTime==-1 || (deltaTime & 0xc0000000) != 0x40000000)//bit flag is not 01<=>right
			deltaTime= 0 + (1<<30);
		else if ((int)(deltaTime & 0x3fffffff)<=dblClkSpeed)
		{
			deltaTime=-1;

			//oneactive = TRUE;
		}
	}
	//middle dbl click
	//////////////////////////////////////////////////////////////////////////		
	if((!middle_old && middle_new))
	{
		if (deltaTime==-1 || (deltaTime & 0xc0000000) != 0x80000000)//bit flag is not 10<=>middle
			deltaTime=0 + (1<<31);
		else if ((int)(deltaTime & 0x3fffffff)<=dblClkSpeed)
		{
			deltaTime=-1;

			//oneactive = TRUE;
		}
	}

	//double click delta time storage
	if (deltaTime != -1)
		if ((int)(deltaTime & 0x3fffffff)>dblClkSpeed)
			deltaTime=-1;
	if(oldDT != deltaTime)
		mElapseTime = deltaTime;


	//MouseMove
	//////////////////////////////////////////////////////////////////////////
	if( ((int)v3.x != 0) || ((int)v3.y != 0) ) {

		if (this->currentmode == NavigationStyle::ZOOMING) {
			//this->zoomByCursor(posn, prevnormalized);
			processed = TRUE;
		}
		else if (this->currentmode == NavigationStyle::PANNING) {
			//float ratio = vp.getViewportAspectRatio();
			panCamera(viewer->getCamera(),campos, posn, prevnormalized);
			processed = TRUE;
		}
		else if (this->currentmode == NavigationStyle::DRAGGING) {
 			VxVector rePos;
 			mInput->GetMouseRelativePosition(rePos);
			//this->addToLog(event->getPosition(), event->getTime());
			this->spin(viewer->getCamera(),rePos);
			processed = TRUE;
		}

	}


	enum {
		BUTTON1DOWN = 1 << 0,
		BUTTON3DOWN = 1 << 1,
		CTRLDOWN =    1 << 2,
		SHIFTDOWN =   1 << 3,
		BUTTON2DOWN = 1 << 4
	};
	unsigned int combo =
		(this->button1down ? BUTTON1DOWN : 0) |
		(this->button2down ? BUTTON2DOWN : 0) |
		(this->button3down ? BUTTON3DOWN : 0) |
		(this->ctrldown ? CTRLDOWN : 0) |
		(this->shiftdown ? SHIFTDOWN : 0);


	switch (combo) {
		  case 0:
			  if (curmode == NavigationStyle::SPINNING) { break; }
			  newmode = NavigationStyle::IDLE;
			  if (this->lockButton1) {
				  this->lockButton1 = FALSE;
				  processed = TRUE;
			  }
			  break;
		  case BUTTON1DOWN:
			  // make sure not to change the selection when stopping spinning
			  if (curmode == NavigationStyle::SPINNING || this->lockButton1)
				  newmode = NavigationStyle::IDLE;
			  else
				  newmode = NavigationStyle::SELECTION;
				// newmode = NavigationStyle::DRAGGING;
			  break;
		  case BUTTON3DOWN:
			  if (curmode == NavigationStyle::SPINNING) { break; }
			  else if (newmode == NavigationStyle::ZOOMING) { break; }
			  newmode = NavigationStyle::PANNING;

			  if (curmode == NavigationStyle::DRAGGING) {
				  if (doSpin()) {
					  newmode = NavigationStyle::SPINNING;
					  break;
				  }
			  }
			  break;
		  case CTRLDOWN|BUTTON1DOWN:
			  newmode = NavigationStyle::DRAGGING;
			  break;
		  case SHIFTDOWN|BUTTON2DOWN:
			  newmode = NavigationStyle::PANNING;
			  break;
		  case CTRLDOWN|SHIFTDOWN|BUTTON2DOWN:
			  newmode = NavigationStyle::ZOOMING;
			  break;

		  default:

			  break;
	}


	if (newmode != curmode) {
		this->setViewingMode(newmode);
	}


	return true;
}

#undef PRIVATE
#undef PUBLIC
